Skip to content

v8: Fix libwee8.a dropping symbols from duplicate-basename objects - #5138

Merged
phlax merged 3 commits into
envoyproxy:mainfrom
dcillera:fix-link-undefined
Aug 20, 2026
Merged

v8: Fix libwee8.a dropping symbols from duplicate-basename objects#5138
phlax merged 3 commits into
envoyproxy:mainfrom
dcillera:fix-link-undefined

Conversation

@dcillera

Copy link
Copy Markdown
Contributor

The fat-archive rule extracted each dep's .lo/.a with ar x and re-archived the members by basename. V8 emits 12 objects that share a basename with a twin compiled from a same-named source in another directory (heap, factory, allocation, free-list, sweeper, assembler, utils, objects-printer, ieee754, logging, platform, snapshot). Extracting to the filesystem clobbered one object of each pair, so libwee8.a carried 1158 members but only 1146 distinct contents -- silently dropping every symbol those 12 objects defined (v8::internal::VirtualMemory::~, Factory::NewSymbol, Heap::CollectAllGarbage, HeapObjectIterator, GetCurrentStackPosition, ...). Consumers such as Envoy then failed to link with undefined-symbol errors for exactly those symbols.

Collect the distinct object Files from each LibraryToLink directly (pic_objects, falling back to objects), dedup by full path so both twins are kept, exclude abseil/icu by object path, and archive them straight into libwee8.a via ar Drcs OUT @params. The result carries duplicate member basenames exactly like V8's own .lo, which links correctly because the linker resolves members by content, not filesystem name. The @file response file avoids ARG_MAX with ~1200 objects.

Verified: x86_64 libcxx defined symbols 91,736 -> 111,541 and aarch64 libcxx independently.

@netlify

netlify Bot commented Aug 20, 2026

Copy link
Copy Markdown

Deploy Preview for nifty-bassi-e26446 ready!

Name Link
🔨 Latest commit aa85b9e
🔍 Latest deploy log https://app.netlify.com/projects/nifty-bassi-e26446/deploys/6a871836cb074e0008602142
😎 Deploy Preview https://deploy-preview-5138--nifty-bassi-e26446.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@phlax phlax left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

posting bot review

Things I'd want confirmed

  • excluded (exclude_lib_prefixes) is now matched against object paths rather than library paths. If those strings were written to match libabseil…a/libicu…a filenames, they'll no longer match …/absl/base/…/foo.pic.o and abseil/icu objects will silently get pulled into libwee8.a (bloat + ODR/duplicate-symbol risk for consumers). Worth verifying the actual attr values match on directory components (e.g. com_google_absl, icu), not archive names.
  • objs = lib.pic_objects if lib.pic_objects else lib.objects — for a library that has both, this takes only PIC, which is intended; but if a dep is alwayslink or splits objects across the two lists, non-PIC objects are dropped without a diagnostic. A comment or an explicit assertion would help the next reader.
  • The params file is written with "\n".join(...) and no trailing newline. Both llvm-ar and GNU ar handle this, but a trailing \n is free insurance.
  • ar Drcs + @params produces an archive with duplicate member names; ar t output is now ambiguous and ar x on the result would clobber again. Might be worth a one-line note in the rule doc so nobody "fixes" this later.

dcillera and others added 2 commits August 20, 2026 16:43
The fat-archive rule extracted each dep's .lo/.a with `ar x` and
re-archived the members by basename. V8 emits 12 objects that share a
basename with a twin compiled from a same-named source in another
directory (heap, factory, allocation, free-list, sweeper, assembler,
utils, objects-printer, ieee754, logging, platform, snapshot). Extracting
to the filesystem clobbered one object of each pair, so libwee8.a carried
1158 members but only 1146 distinct contents -- silently dropping every
symbol those 12 objects defined (v8::internal::VirtualMemory::~,
Factory::NewSymbol, Heap::CollectAllGarbage, HeapObjectIterator,
GetCurrentStackPosition, ...). Consumers such as Envoy then failed to
link with undefined-symbol errors for exactly those symbols.

Collect the distinct object Files from each LibraryToLink directly
(pic_objects, falling back to objects), dedup by full path so both twins
are kept, exclude abseil/icu by object path, and archive them straight
into libwee8.a via `ar Drcs OUT @params`. The result carries duplicate
member basenames exactly like V8's own .lo, which links correctly because
the linker resolves members by content, not filesystem name. The @file
response file avoids ARG_MAX with ~1200 objects.

Verified: x86_64 libcxx defined symbols 91,736 -> 111,541 and aarch64
libcxx independently.

Signed-off-by: Dario Cillerai <dcillera@redhat.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Dario Cillerai <dcillera@redhat.com>
Signed-off-by: Dario Cillerai <dcillera@redhat.com>
@dcillera
dcillera force-pushed the fix-link-undefined branch from 739ab9b to f10e743 Compare August 20, 2026 14:43
@dcillera

Copy link
Copy Markdown
Contributor Author

posting bot review

Things I'd want confirmed

  • excluded (exclude_lib_prefixes) is now matched against object paths rather than library paths. If those strings were written to match libabseil…a/libicu…a filenames, they'll no longer match …/absl/base/…/foo.pic.o and abseil/icu objects will silently get pulled into libwee8.a (bloat + ODR/duplicate-symbol risk for consumers). Worth verifying the actual attr values match on directory components (e.g. com_google_absl, icu), not archive names.
  • objs = lib.pic_objects if lib.pic_objects else lib.objects — for a library that has both, this takes only PIC, which is intended; but if a dep is alwayslink or splits objects across the two lists, non-PIC objects are dropped without a diagnostic. A comment or an explicit assertion would help the next reader.
  • The params file is written with "\n".join(...) and no trailing newline. Both llvm-ar and GNU ar handle this, but a trailing \n is free insurance.
  • ar Drcs + @params produces an archive with duplicate member names; ar t output is now ambiguous and ar x on the result would clobber again. Might be worth a one-line note in the rule doc so nobody "fixes" this later.

Point 1 is verified safe — and the reviewer's worry doesn't apply to our actual attr values. A comment will be added for clarification. Evidence:

  • 1257 total objects; 99 are abseil, and all 99 match abseil-cpp+. So abseil-cpp+ is a directory component in every abseil
    object path (.../external/abseil-cpp+/absl/container/_objs/.../raw_hash_set.pic.o), exactly the kind of match the
    reviewer wanted — it's the bzlmod canonical repo name, not an archive filename.
  • icu contributes 0 objects (this is the noicu V8 build). The only "unicode"-ish object is V8's own
    external/v8+/_objs/v8_libshared_noicu/unicode.pic.o — a legitimate V8 object, correctly not excluded.
  • 1257 − 99 = 1158, matching the built archive exactly. No abseil/icu leaks in.

The other requests will be addressed in an additional commit:
2. pic_objects if … else objects. pic_objects and objects are the same TUs compiled two ways, not a partition — taking both would double every object. Added a comment stating this and why PIC is preferred (matches the prebuilt ABI), with non-PIC as fallback.

  1. Trailing newline. Done — "\n".join(...) + "\n", with a comment noting it's free insurance.

  2. Intentional duplicate member names. Expanded the rule doc to warn that duplicate basenames are required (V8 emits same-named objects from different dirs, like its own .lo), that ar t output is ambiguous by design, and that no one should "dedup" or extract-and-rearchive (ar x) — that's exactly the clobbering bug this fixes.

Documentation and robustness follow-ups from PR envoyproxy#5138 review; no change to
the archive contents (still 1158 objects, 12 intentional basename collisions).

- Document that exclude_lib_prefixes matches OBJECT paths and that the
  defaults ("abseil-cpp+", "icu+") are the canonical bzlmod repo directory
  components, so they match every abseil/icu object. Verified: all 99 abseil
  objects contain "abseil-cpp+"; the noicu build pulls in zero icu objects.
- Explain that pic_objects/objects are the same TUs compiled two ways (not a
  partition), so selecting one list is correct and PIC is preferred.
- Write the params file with a trailing newline as insurance for archivers
  that expect newline-terminated entries.
- Expand the rule doc to warn that duplicate member basenames are intentional
  and required (matches V8's own .lo); do not dedup by basename or
  extract-and-rearchive (ar x), which reintroduces the symbol-dropping bug.

Signed-off-by: Dario Cillerai <dcillera@redhat.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@phlax phlax left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks @dcillera

@phlax
phlax merged commit 16a3f15 into envoyproxy:main Aug 20, 2026
62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants